﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
using System.Web;

using System.Data;
using System.Text;
using SmartProject.Data;

namespace SmartProject.BusinessObjects
{
    /// <summary>
    /// Wraps all the functions of creating, modifying, removing, loading
    /// etc work/works into a single class.
    /// </summary>
    public class Work : Entity
    {
        private readonly TimeType _estTimeType = new TimeType();
        private readonly TimeType _actualTimeType = new TimeType();
        private readonly Status _status = new Status();
        private readonly Severity _severity = new Severity();
        private readonly Priority _priority = new Priority();
        private readonly Category _category = new Category();

        /// <summary>
        /// Creates a new instance of the Work class.
        /// </summary>
        public Work()
        {
            // Using the helper reference class, we can pre-define some values
            // for the various statues, priority/severity levels and categories.
            _status.DataParameterName = "StatusId";
            _status.Parent = this;
            _severity.DataParameterName = "PrioritySeverityId";
            _severity.Parent = this;
            _priority.DataParameterName = "PrioritySeverityId";
            _priority.Parent = this;
            _category.DataParameterName = "CategoryId";
            _category.Parent = this;
            _estTimeType.DataParameterName = "EstTimeTypeId";
            _estTimeType.Parent = this;
            _actualTimeType.DataParameterName = "ActualTimeTypeId";
            _actualTimeType.Parent = this;

            DataParameter[] dataParameters = new DataParameter[26];

            dataParameters[0] = new DataParameter("WorkId", DataType.Integer);
            dataParameters[1] = new DataParameter("OwnerId", DataType.Integer);
            dataParameters[2] = new DataParameter("DeveloperId", DataType.Integer);
            dataParameters[3] = new DataParameter("ProductId", DataType.Integer);
            dataParameters[4] = new DataParameter("SprintId", DataType.Integer);
            dataParameters[5] = new DataParameter("EstTime", DataType.Integer);
            dataParameters[6] = new DataParameter("ActualTime", DataType.Integer);
            dataParameters[7] = new DataParameter("PrioritySeverityId", DataType.Integer);
            dataParameters[8] = new DataParameter("StatusId", DataType.Integer);
            dataParameters[9] = new DataParameter("CategoryId", DataType.Integer);
            dataParameters[10] = new DataParameter("Description", 200);
            dataParameters[11] = new DataParameter("DueDate", DataType.DateTime);
            dataParameters[16] = new DataParameter("Created", DataType.DateTime);
            dataParameters[18] = new DataParameter("Assigned", DataType.DateTime);
            dataParameters[19] = new DataParameter("Approved", DataType.DateTime);
            dataParameters[20] = new DataParameter("Completed", DataType.DateTime);
            dataParameters[21] = new DataParameter("Active", DataType.Boolean);
            dataParameters[22] = new DataParameter("EstTimeTypeId", DataType.Integer);
            dataParameters[23] = new DataParameter("ActualTimeTypeId", DataType.Integer);
            // This are custom fields for loading work item/items.
            dataParameters[12] = new DataParameter("Criteria", 1000);
            dataParameters[13] = new DataParameter("Id", DataType.Integer);
            dataParameters[14] = new DataParameter("OwnerName", 350);
            dataParameters[15] = new DataParameter("DeveloperName", 350);
            dataParameters[17] = new DataParameter("ProductName", 150);
            dataParameters[24] = new DataParameter("SprintName", 200);
            dataParameters[25] = new DataParameter("UserId", DataType.Integer);

            base.Initialize(dataParameters);
            base.BusinessRules.Add(new BusinessRules.WorkStatusToInProgress());
            base.BusinessRules.Add(new BusinessRules.SprintPreConditions());
            base.BusinessRules.Add(new BusinessRules.RemoveWorkReferences());
        }

        public Severity Severities
        {
            get { return _severity; }
        }

        public Category Categories
        {
            get { return _category; }
        }

        public Priority Priorities
        {
            get { return _priority; }
        }

        public Status Statuses
        {
            get { return _status; }
        }

        public TimeType EstTimeType
        {
            get { return _estTimeType; }
        }

        public TimeType ActualTimeType
        {
            get { return _actualTimeType; }
        }

        /// <summary>
        /// Adds a new work item.
        /// </summary>
        public override void Save()
        {
            base.SetAttribute("StatusId", _status.GetId("New", false));
            base.Run("smartProject_AddWork");
        }

        /// <summary>
        /// Update an existing work item.
        /// </summary>
        public override void Update()
        {
            base.Run("smartProject_UpdateWork");
        }

        public void StartWork()
        {
            base.SetAttribute("StatusId", _status.GetId("In Progress", false));
            base.Run("smartProject_UpdateWorkStatus");
        }

        public void HoldWork()
        {
            base.SetAttribute("StatusId", _status.GetId("On Hold", false));
            base.Run("smartProject_UpdateWorkStatus");
        }

        /// <summary>
        /// When a developer gets assigned to a work item, the status of the work
        /// item changes to Assigned.
        /// </summary>
        public void UpdateDeveloper()
        {
            base.SetAttribute("StatusId", _status.GetId("Assigned", false));
            base.Run("smartProject_UpdateWorkDeveloperId");
        }

        public void UpdateSprint()
        {
            base.Run("smartProject_UpdateWorkSprint");
        }

        public DataTable LoadWorks(string conditional, string orderBy, bool isAscending)
        {
            StringBuilder sql = new StringBuilder();

            if (!String.IsNullOrEmpty(conditional))
            {
                sql.Append(" AND ");
                sql.Append(conditional);
            }

            if (!String.IsNullOrEmpty(orderBy))
            {
                sql.Append(" ORDER BY ");
                sql.Append(orderBy);
                if (isAscending)
                {
                    sql.Append(" ASC; ");
                }
                else
                {
                    sql.Append(" DESC; ");
                }
            }

            SetAttribute("Criteria", sql.ToString());
            return base.Find("smartProject_GetWorks");
        }

        public override void Remove()
        {
            base.Run("smartProject_RemoveWork");
        }

        /// <summary>
        /// Loads a work item based on a specific work item Id.
        /// </summary>
        public override void Load()
        {
            base.Load("smartProject_GetWork");
        }

        /// <summary>
        /// Loads work items related to a Sprint Cycle that are completed.
        /// </summary>
        /// <returns>DataTable containing the work item rows.</returns>
        public DataTable LoadSprintWorks()
        {
            return base.Find("smartProject_GetCompletedSprintWorks");
        }

        public void Approve()
        {
            base.SetAttribute("StatusId", _status.GetId("Approved", false));
            base.Run("smartProject_UpdateWorkApproved");
        }

        public void Complete()
        {
            base.Run("smartProject_UpdateWorkComplete");
        }

        /// <summary>
        /// Discard a work that was in-progress and make it a new item 
        /// (to be re-assigned).
        /// </summary>
        public void Discard()
        {
            base.SetAttribute("StatusId", _status.GetId("New", false));
            base.Run("smartProject_UpdateWorkDiscard");
        }

        public void InComplete()
        {
            base.SetAttribute("StatusId", _status.GetId("In Progress", false));
            base.Run("smartProject_UpdateWorkInComplete");
        }
    }
}
